54. 绘制曲线图

本章概要

  • 学习材料:同频中性价格/成交量与周度移动平均教学示例。
  • 本章任务:运行 fig-dual-y-axisplot-moving-avg-output,比较标准化单轴、双轴和2/3周均线交叉。
  • 完成后你将得到:带“教学示例,非市场观测”的曲线、图例、统计表和交叉列。
  • 自我检查:检查索引对齐、标准化均值近零与交叉布尔等价;依据标识缺失时先检查原因。
  • 拓展练习:把移动平均交叉拓展应用到另一中性序列。

曲线图:数据可视化的基石

曲线图(Line Plot)是最基础也是最重要的数据可视化形式之一。

在金融与商业领域,曲线图帮助我们:

  • 观察趋势:识别价格的上升、下降、震荡趋势
  • 发现模式:识别季节性、周期性模式
  • 比较表现:对比不同资产的表现
  • 监控变化:实时跟踪关键指标的变化

曲线图的数学基础

曲线图本质上是函数的可视化

\[ \large y = f(x) \]

在金融时间序列中:

  • 自变量 \(x\):时间 \(t\)
  • 因变量 \(y\):价格、收益率、成交量等

连续与离散的处理

  • 理论上,价格是离散的(仅在交易时刻有定义)
  • 为了可视化,我们用线段连接相邻点,形成连续曲线
  • 这种线性插值假设价格在交易间隔内平滑变化

运行前预测|平台任务1:等额本息还款曲线

  • 输入预测:运行前先写出 rnprinciplepay_month 的业务含义、数据类型或取值范围,并判断哪一个输入最可能改变结果。
  • 结果预测:不展开答案,先预测将得到“在等额本息规则下丁先生每月偿还的金额”相关结果;同时写出方向、数量级或表格/图形结构。
  • 完成要求:能独立说明本任务从输入到“平台任务1:等额本息还款曲线”结果的关键步骤,原样录入平台代码并得到可核对的运行结果。

⭐ 平台任务1:等额本息还款曲线

展开完整代码(投影默认折叠)
# 注:numpy_financial包本地未安装,但平台已经内置
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import numpy as np  # 导入NumPy数值计算库
import pandas as pd  # 导入Pandas数据分析库
import matplotlib.pyplot as plt    #导入matplotlab的子模块pyplot
import  numpy_financial as nmf  # 导入NumPy库
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置Matplotlib全局参数

r = 0.049 #贷款的年利率
n = 30   #贷款的期限(年)
principle = 6e6 #贷款的本金
pay_month = nmf.pmt(rate=r/12,nper=n*12,pv=principle,fv=0,when="end")  # 计算等额本息月供金额
print("在等额本息规则下丁先生每月偿还的金额",-round(pay_month,2))  # 输出在等额本息规则下丁先生每月偿还的金额
t = np.arange(n*12)+1  #生成一个包含每次还款期限长度的数组
principle_pay_month = nmf.ppmt(rate=r/12,per=t,nper=n*12,pv=principle,fv=0,when="end") #计算每月偿还的本金额
interest_pay_month = nmf.ipmt(rate=r/12,per=t,nper=n*12,pv=principle,fv=0,when="end")  #计算每月偿还的利息额
pay_month_array = pay_month*np.ones_like(principle_pay_month) #创建一个每月偿还的数组
plt.figure(figsize=(9,6))  # 创建图形画布
plt.plot(t,-pay_month_array,"r-",label=u"每月偿还金额",lw=2.5)  # 绘制折线图
plt.plot(t,-principle_pay_month,"m--",label=u"每月偿还本金金额",lw=2.5)  # 绘制折线图
plt.plot(t,-interest_pay_month,"b--",label =u"每月产股韩利息金额",lw=2.5)  # 绘制折线图
plt.xticks(fontsize=14)  # 设置X轴刻度标签
plt.xlabel(u"逐次偿还的期限(月)",fontsize=14)  # 设置X轴标签
plt.yticks(fontsize=13)  # 设置Y轴刻度标签
plt.ylabel(u"金额",fontsize=14)  # 设置Y轴标签
plt.title(u"等额本息还款规则下每月偿还的金额以及本金额与利息额")  # 设置图表标题
plt.legend(loc=0,fontsize=13)  # 添加图例
plt.grid()  # 显示网格线
plt.savefig("1.png")  # 保存图形至文件

任务复盘|平台任务1:等额本息还款曲线

运行后核对:核对 rnprinciplepay_month 是否按预测参与运算,实际输出是否与预测一致;若不一致,先检查类型、单位、索引/字段和运算顺序。

拓展练习:把数据替换为一个中国企业或市场序列,改变一个分组或时间窗口;说明图形结论是否改变,以及为何。

运行前预测|平台任务2:不同利率下的月供变化

  • 输入预测:运行前先写出 rnprincipler_list 的业务含义、数据类型或取值范围,并判断哪一个输入最可能改变结果。
  • 结果预测:不展开答案,先预测将得到pay_month_list 的结果;同时写出方向、数量级或表格/图形结构。
  • 完成要求:能独立说明本任务从输入到“平台任务2:不同利率下的月供变化”结果的关键步骤,原样录入平台代码并得到可核对的运行结果。

⭐ 平台任务2:不同利率下的月供变化

展开完整代码(投影默认折叠)
# 注:numpy_financial包本地未安装,但平台已经内置
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import numpy as np  # 导入NumPy数值计算库
import matplotlib.pyplot as plt  #导入matplotlab的子模块pyplot
import numpy_financial as nmf  # 导入NumPy库
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置Matplotlib全局参数

r = 0.049 #贷款的年利率
n = 30   #贷款的期限(年)
principle = 6e6 #贷款的本金

r_list = np.linspace(0.02,0.08,100) #生成贷款利率的一个数组
pay_month = nmf.pmt(rate=r/12,nper=n*12,pv=principle,fv=0,when="end")  # 计算等额本息月供金额
pay_month_list = nmf.pmt(rate=r_list/12,nper=n*12,pv=principle,fv=0,when="end") #计算不同贷款利率条件下的每月偿还本息之和
plt.figure(figsize=(9,6))  # 创建图形画布
plt.plot(r_list,-pay_month_list,"r-",label=u"每月偿还金额",lw=2.5)  # 绘制折线图
plt.plot(r,-pay_month,"bo",label=u"贷款利率4.9%的每月偿还金额")  # 绘制折线图
plt.xticks(fontsize=14)  # 设置X轴刻度标签
plt.xlabel(u"贷款利率",fontsize=14)  # 设置X轴标签
plt.yticks(fontsize=14)  # 设置Y轴刻度标签
plt.ylabel(u"金额",fontsize=14,rotation=90)  # 设置Y轴标签
plt.legend(loc=0,fontsize=13)  # 添加图例
plt.grid()  # 显示网格线
plt.savefig("2.png")  # 保存图形至文件

任务复盘|平台任务2:不同利率下的月供变化

运行后核对:核对 rnprincipler_list 是否按预测参与运算,实际输出是否与预测一致;若不一致,先检查类型、单位、索引/字段和运算顺序。

拓展练习:把数据替换为一个中国企业或市场序列,改变一个分组或时间窗口;说明图形结论是否改变,以及为何。

运行前预测|平台任务3:等额本金还款曲线

  • 输入预测:运行前先写出 rnprinciplet 的业务含义、数据类型或取值范围,并判断哪一个输入最可能改变结果。
  • 结果预测:不展开答案,先预测将得到pay_total_month 的结果;同时写出方向、数量级或表格/图形结构。
  • 完成要求:能独立说明本任务从输入到“平台任务3:等额本金还款曲线”结果的关键步骤,原样录入平台代码并得到可核对的运行结果。

⭐ 平台任务3:等额本金还款曲线

展开完整代码(投影默认折叠)
# 注:numpy_financial包本地未安装,但平台已经内置
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
import numpy as np  # 导入NumPy数值计算库
import matplotlib.pyplot as plt #导入matplotlab的子模块pyplot
import numpy_financial as nmf  # 导入NumPy库
plt.rcParams["font.sans-serif"] = ["SimHei"]  # 设置Matplotlib全局参数

r = 0.049 #贷款的年利率
n = 30  #贷款的期限(年)
principle = 6e6 #贷款的本金
t = np.arange(n*12)+1 #生成一个包含每次还款期限长度的数组
prin_month = principle/(n*12) #计算等额本金还款规则下的每月本金还款额
prin_month_array = np.ones(n*12)*prin_month #生成一个每月本金还款额的数组
int_month_array = np.zeros_like(prin_month_array) #生成存放每月利息还款额的初始数组
for i in np.arange(n*12):  # 遍历np.arange(n*12)中的每个i
 int_month_array[i] = (principle-i*prin_month)*r/12 #计算逐月支付的利息额
pay_total_month = prin_month_array+int_month_array #j计算等额本金还款规则下的每月还款总额
plt.figure(figsize=(9,6))  # 创建图形画布
plt.plot(t,pay_total_month,"m-",label=u"每月偿还金额",lw=2.5)  # 绘制折线图
plt.plot(t,prin_month_array,"y--",label=u"每月偿还本金额",lw=2.5)  # 绘制折线图
plt.plot(t,int_month_array,"c--",label =u"每月偿还利息额",lw=2.5)  # 绘制折线图
plt.xticks(fontsize=14)  # 设置X轴刻度标签
plt.xlabel(u"逐次偿还的期限(月)",fontsize=14)  # 设置X轴标签
plt.yticks(fontsize=14)  # 设置Y轴刻度标签
plt.ylabel(u"金额",fontsize=14,rotation=90)  # 设置Y轴标签
plt.title(u"等额本金还款规则下每月偿还的金额以及本金额与利息额",fontsize=14)  # 设置图表标题
plt.legend(loc=0,fontsize=13)  # 添加图例
plt.grid()  # 显示网格线
plt.savefig("3.png")  # 保存图形至文件

任务复盘|平台任务3:等额本金还款曲线

运行后核对:核对 rnprinciplet 是否按预测参与运算,实际输出是否与预测一致;若不一致,先检查类型、单位、索引/字段和运算顺序。

拓展练习:把数据替换为一个中国企业或市场序列,改变一个分组或时间窗口;说明图形结论是否改变,以及为何。

基础曲线图:核心函数 plt.plot()

绘制基础曲线图的核心步骤:

  1. 导入库:matplotlib.pyplot
  2. 准备数据:X轴(时间)和Y轴(数值)
  3. 调用 plt.plot(x, y) 绘制曲线
  4. 添加装饰:标题、轴标签、网格线等
  5. 显示图形:plt.show()

中文字体设置(必备)

在绘制包含中文的图表前,必须设置中文字体:

plt.rcParams['font.sans-serif'] = ['Source Han Serif SC']
plt.rcParams['axes.unicode_minus'] = False
  • Source Han Serif SC:思源宋体,确保中文正常显示
  • unicode_minus:解决负号 - 显示为方块的问题

基础曲线图示例:股价走势

展开实现代码
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

plt.rcParams['font.sans-serif'] = ['Source Han Serif SC']
plt.rcParams['axes.unicode_minus'] = False

# 生成固定的三十期纯教学示例,不代表真实企业或投资情况
np.random.seed(42)  # 固定教学示例随机种子以便重新运行
dates = pd.date_range('2024-01-01', periods=30)
prices = [1850 + i * 2 + np.random.randn() * 10 for i in range(30)]
df = pd.DataFrame({'日期': dates, '收盘价': prices})

plt.figure(figsize=(12, 4.2))
plt.plot(df['日期'], df['收盘价'], linewidth=2, color='#2E86AB')
plt.title('教学示例,非市场观测|中性价格序列', fontsize=16, fontweight='bold')  # 标明图形不对应真实证券
plt.xlabel('日期', fontsize=12)
plt.ylabel('收盘价(元)', fontsize=12)
plt.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
教学示例,非市场观测。三十期中性序列仅演示日期轴、线型与标签。
Figure 1: 教学示例,非市场观测|基础曲线图

plt.plot() 常用参数

参数 说明 示例
linewidth 线宽,数值越大线越粗 linewidth=2
color 颜色(十六进制/RGB/英文名) color='#2E86AB'
linestyle 线型 '-' 实线、'--' 虚线、':' 点线
label 图例标签 label='收盘价'
alpha 透明度(0~1) alpha=0.7

图表装饰函数一览

函数 作用
plt.title() 设置图表标题
plt.xlabel() / plt.ylabel() 设置轴标签
plt.grid() 显示网格线
plt.legend() 显示图例
plt.xticks(rotation=45) 旋转X轴刻度标签
plt.tight_layout() 自动调整布局

多条曲线对比:在同一图中绘制多条线

核心思路:多次调用 plt.plot(),每次绘制一条曲线。

关键设计要点:

  • 颜色选择:使用对比度高、易于区分的颜色
  • 线宽区分:主要数据用较粗的线,次要数据用较细的线
  • 图例plt.legend(loc='best') 自动选择最佳位置

多条曲线示例:三个中性序列对比

展开完整代码
stocks_data = pd.DataFrame({
    '日期': dates,
    '资产A': [100 + i * 0.15 + np.random.randn() * 0.8 for i in range(30)],  # 生成A序列教学示例
    '资产B': [80 + i * 0.08 + np.random.randn() * 0.5 for i in range(30)],  # 生成B序列教学示例
    '资产C': [40 + i * 0.03 + np.random.randn() * 0.2 for i in range(30)]  # 生成C序列教学示例
})

plt.figure(figsize=(12, 4.2))
plt.plot(stocks_data['日期'], stocks_data['资产A'],  # 绘制中性A序列
         label='资产A|教学示例,非市场观测', linewidth=2, color='#E3120B')  # 设置A序列样式与依据标签
plt.plot(stocks_data['日期'], stocks_data['资产B'],  # 绘制中性B序列
         label='资产B|教学示例,非市场观测', linewidth=2, color='#008080')  # 设置B序列样式与依据标签
plt.plot(stocks_data['日期'], stocks_data['资产C'],  # 绘制中性C序列
         label='资产C|教学示例,非市场观测', linewidth=2, color='#2C3E50')  # 设置C序列样式与依据标签

plt.title('教学示例,非市场观测|中性序列走势对比', fontsize=16, fontweight='bold')  # 标明仅比较教学示例
plt.xlabel('日期', fontsize=12)
plt.ylabel('收盘价(元)', fontsize=12)
plt.legend(loc='best', fontsize=11, title='教学示例,非市场观测')  # 在移动平均图例标题持续声明依据边界
plt.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
教学示例,非市场观测。三个中性序列仅演示量级、颜色和图例。
Figure 2: 教学示例,非市场观测|多条曲线对比

多曲线对比注意事项

当数据量级差异大时(如教学示例 A 为100量级、C为40量级),考虑:

  • 双Y轴:左右各一个Y轴,对应不同量级
  • 归一化:将所有数据转换为相对百分比
  • 子图(subplots):分别绘制在不同图中

双Y轴图:展示量价关系

应用场景:同时展示不同量级的数据

  • 价格(几十元) vs 成交量(几千手)
  • 收益率 vs 波动率
  • 股价 vs 技术指标

核心函数:ax1.twinx() 创建共享X轴的右Y轴

双Y轴示例:价格与成交量

展开完整代码
df_dual = pd.DataFrame({
    '日期': dates,
    '收盘价': [45 + i * 0.5 + np.random.randn() * 3 for i in range(30)],
    '成交量': [5000 + i * 100 + np.random.randn() * 500 for i in range(30)]
})

fig, ax1 = plt.subplots(figsize=(12, 4.2))

color1 = '#E3120B'
ax1.set_xlabel('日期', fontsize=12)
ax1.set_ylabel('收盘价(元)', color=color1, fontsize=12)
line1 = ax1.plot(df_dual['日期'], df_dual['收盘价'],
                 color=color1, linewidth=2, label='中性价格|教学示例,非市场观测')  # 在图例保留依据边界
ax1.tick_params(axis='y', labelcolor=color1)
ax1.grid(True, alpha=0.3)

ax2 = ax1.twinx()
color2 = '#008080'
ax2.set_ylabel('成交量(手)', color=color2, fontsize=12)
line2 = ax2.plot(df_dual['日期'], df_dual['成交量'],
                 color=color2, linewidth=2, linestyle='--', label='中性成交量|教学示例,非市场观测')  # 在图例保留依据边界
ax2.tick_params(axis='y', labelcolor=color2)

lines = line1 + line2
labels = [l.get_label() for l in lines]
ax1.legend(lines, labels, loc='best', fontsize=11, title='教学示例,非市场观测')  # 在双轴图例标题持续声明依据边界
plt.title('教学示例,非市场观测|价格与成交量走势', fontsize=16, fontweight='bold')  # 在导出图标题保留依据边界
plt.tight_layout()
plt.show()
教学示例,非市场观测。双Y轴图仅演示中性价格与成交量的不同量纲。
Figure 3: 教学示例,非市场观测|双Y轴价格与成交量

双Y轴使用注意事项

  • 双Y轴可能误导读者,需谨慎使用
  • 明确标注哪个轴对应哪条线(颜色一致)
  • 考虑用子图(subplots)替代,信息更清晰
  • 避免两个Y轴刻度范围差异过大

填充区域图:展示数据区间

plt.fill_between() 用于填充两条曲线之间的区域。

金融应用

  • 布林带:移动平均线 ± 标准差
  • 置信区间:统计模型预测的上下限
  • 期权策略:到期时的盈亏区间
  • VaR区间:在险价值的区间表示

填充区域图示例:预设区间教学示例

展开实现代码
df_area = pd.DataFrame({
    '日期': dates,
    '价格': [100 + i + np.random.randn() * 3 for i in range(30)],
    '上限': [105 + i + np.random.randn() * 2 for i in range(30)],
    '下限': [95 + i + np.random.randn() * 2 for i in range(30)]
})

plt.figure(figsize=(12, 4.2))
plt.plot(df_area['日期'], df_area['价格'],
         label='中性中心路径|教学示例,非市场观测', linewidth=2, color='#2C3E50')  # 使用中性路径标签声明输入边界
plt.fill_between(df_area['日期'], df_area['下限'], df_area['上限'],
                 alpha=0.3, color='#008080', label='预设区间|教学示例,非市场观测')  # 禁止把预设带写成模型预测
plt.title('教学示例,非市场观测|中性路径与预设区间', fontsize=16, fontweight='bold')  # 在导出图标题保留依据边界
plt.xlabel('日期', fontsize=12)
plt.ylabel('价格(元)', fontsize=12)
plt.legend(loc='best', fontsize=11, title='教学示例,非市场观测')  # 在移动平均图例标题持续声明依据边界
plt.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
教学示例,非市场观测。填充区域图仅演示中性序列与预设区间。
Figure 4: 教学示例,非市场观测|填充区域图

fill_between 常用参数

参数 说明 示例
alpha 透明度(0~1),越小越透明 alpha=0.3
color 填充颜色 color='#008080'
where 条件填充,只填充满足条件的区域 where=(y1 > y2)
interpolate 在边界处插值,使填充更平滑 interpolate=True

堆叠面积图:展示构成变化

plt.stackplot() 绘制堆叠面积图,展示各部分随时间的变化。

金融应用

  • 资产配置:股票、债券、现金的配置变化
  • 收入构成:主营业务收入、其他业务收入
  • 市场份额:不同公司在市场中的份额变化

堆叠面积图的数学含义

每层的累积值:

\[ \large y_{\text{total}} = y_1 + y_2 + \cdots + y_n \]

\(i\) 层的显示范围:

\[ \large y_{\text{layer } i} = \sum_{j=1}^{i} y_j \]

堆叠面积图示例:投资组合

展开完整代码
df_portfolio = pd.DataFrame({
    '日期': pd.date_range('2024-01-01', periods=12),
    '股票': [100 + i*5 + np.random.randn()*3 for i in range(12)],
    '债券': [80 + i*2 + np.random.randn()*2 for i in range(12)],
    '现金': [20 + i*0.5 + np.random.randn()*1 for i in range(12)]
})

plt.figure(figsize=(12, 4.2))
plt.stackplot(df_portfolio['日期'],
              df_portfolio['股票'],
              df_portfolio['债券'],
              df_portfolio['现金'],
              alpha=0.8,
              colors=['#E3120B', '#008080', '#F0A700'],
              labels=['股票|教学示例,非市场观测', '债券|教学示例,非市场观测', '现金|教学示例,非市场观测'])  # 在每个图例项保留依据边界
plt.title('教学示例,非市场观测|投资组合资产配置变化', fontsize=16, fontweight='bold')  # 在导出图标题保留依据边界
plt.xlabel('日期', fontsize=12)
plt.ylabel('资产价值(万元)', fontsize=12)
plt.legend(loc='upper left', fontsize=11, title='教学示例,非市场观测')  # 在堆叠图例标题持续声明依据边界
plt.grid(True, alpha=0.3, axis='y')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
教学示例,非市场观测。堆叠面积图仅演示三个中性类别的预设构成。
Figure 5: 教学示例,非市场观测|堆叠面积构成

对数坐标轴:处理指数增长数据

线性坐标:展示绝对值变化

对数坐标:展示相对变化(百分比)

在金融中的意义:

  • 复利效应:对数坐标下,恒定增长率呈直线
  • 收益率比较:不同起始点的资产可直接比较斜率
  • 长期趋势:更适合展示跨越数量级的数据

对数坐标的数学原理

\[ \large \ln(y) = \ln(A \cdot e^{rt}) = \ln(A) + rt \]

在半对数图上,指数增长呈直线,斜率即为增长率 \(r\)

核心函数:ax.semilogy()plt.yscale('log')

对数坐标示例:复利增长

展开完整代码
years = np.arange(2000, 2024)
initial_value = 100
growth_rate = 0.15
values = initial_value * (1 + growth_rate) ** (years - 2000)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4.2))

# 线性坐标(左图)
ax1.plot(years, values, linewidth=2, color='#E3120B')
ax1.set_title('教学示例,非市场观测|线性坐标', fontsize=14, fontweight='bold')  # 在左面板保留依据边界
ax1.set_xlabel('年份', fontsize=12)
ax1.set_ylabel('价值(元)', fontsize=12)
ax1.grid(True, alpha=0.3)

# 对数坐标(右图)
ax2.semilogy(years, values, linewidth=2, color='#008080')
ax2.set_title('教学示例,非市场观测|对数坐标', fontsize=14, fontweight='bold')  # 在右面板保留依据边界
ax2.set_xlabel('年份', fontsize=12)
ax2.set_ylabel('价值(元,对数)', fontsize=12)
ax2.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()
教学示例,非市场观测。左右面板仅演示同一预设复利序列在线性轴与对数轴上的差异。
Figure 6: 教学示例,非市场观测|复利序列的对数Y轴

对数坐标示例:结果核对

展开结果核对代码
print('教学示例,非市场观测|复利序列核对')  # 在孤立输出表头保留依据边界
print(f'初始值: {initial_value}元')
print(f'年化增长率: {growth_rate:.1%}')
print(f'2023年价值: {values[-1]:.2f}元')
print(f'总增长倍数: {values[-1]/initial_value:.1f}倍')
教学示例,非市场观测|复利序列核对
初始值: 100元
年化增长率: 15.0%
2023年价值: 2489.15元
总增长倍数: 24.9倍

金融应用:移动平均线

简单移动平均(SMA)是技术分析的基础:

\[ \large \text{SMA}_t = \frac{1}{n}\sum_{i=0}^{n-1} P_{t-i} \]

核心函数:.rolling(window=n).mean()

常用周期:MA5(短期)、MA20(中期)、MA60(长期)

曲线事件:上穿与下穿

  • 上穿事件:短期均线由下向上穿过长期均线 → CROSS_UP 图形标签
  • 下穿事件:短期均线由上向下穿过长期均线 → CROSS_DOWN 图形标签

两者只描述两条滞后曲线的形状关系,不能作为收益预测或投资依据。实际应用还需要检查数据时间、复权方法、样本外表现、成本和不确定性。

局限性

  • 滞后性:基于历史价格,信号滞后
  • 震荡市场中频繁产生错误信号
  • 参数敏感性:不同周期效果差异大

移动平均线示例:含交叉信号

展开完整参考实现
figure, moving_axis = plt.subplots(figsize=(10.5, 4.4))  # 创建单一宽幅投影视图
moving_axis.plot(df_price['日期'], df_price['收盘价'], label='收盘价', linewidth=1.5, color='#2C3E50', alpha=0.7)  # 绘制原始序列
moving_axis.plot(df_price['日期'], df_price['MA5'], label='MA5', linewidth=1.8, color='#E3120B')  # 绘制短期均线
moving_axis.plot(df_price['日期'], df_price['MA20'], label='MA20', linewidth=1.8, color='#008080')  # 绘制长期均线
moving_axis.scatter(df_price.loc[golden_cross, '日期'], df_price.loc[golden_cross, 'MA5'], color='red', s=100, marker='^', label='金叉', zorder=5)  # 标注上穿
moving_axis.scatter(df_price.loc[death_cross, '日期'], df_price.loc[death_cross, 'MA5'], color='green', s=100, marker='v', label='死叉', zorder=5)  # 标注下穿
moving_axis.set_title('教学示例,非市场观测|移动平均交叉', fontsize=16, fontweight='bold')  # 声明依据边界
moving_axis.set_xlabel('日期', fontsize=12)  # 标注横轴
moving_axis.set_ylabel('价格(元)', fontsize=12)  # 标注纵轴
moving_axis.legend(loc='best', fontsize=11, title='教学示例,非市场观测')  # 合并为一个图例
moving_axis.grid(True, alpha=0.3)  # 添加参考网格
moving_axis.tick_params(axis='x', rotation=30)  # 旋转日期刻度避免拥挤
figure.tight_layout()  # 调整单图布局
plt.show()  # 显示完整图形

教学示例,非市场观测。中性序列、两条移动平均线及交叉标记。

本章小结

图表类型 核心函数 适用场景
基础曲线图 plt.plot() 单条时间序列
多条曲线 多次 plt.plot() 对比不同资产
双Y轴图 ax1.twinx() 不同量级数据
填充区域图 plt.fill_between() 预测区间/布林带
堆叠面积图 plt.stackplot() 构成变化
对数坐标 ax.semilogy() 指数增长数据

随堂练习

  • 问题 1|怎样完成本章分析?:给定两条同频序列,完成单轴/标准化对比;若另做双 Y 轴,写出轴单位、图例与标准化图核对。
  • 问题 2|结果说明什么?:说明 fig-basic-line-plot 使用了哪些数据、怎样绘图以及图形展示了什么;引用一个实际字段或数值,并指出哪些数据问题可能导致误读。
  • 问题 3|换一个情境,怎样继续应用?:对中性序列计算2周/3周移动平均与交叉状态,写出原值、两条均线、交叉列及索引对齐检查;所有可见标识明示“教学示例,非市场观测”。
  • 作答提示:请完成三道题,并在回答中引用实际运行结果;拓展练习中不要把课堂示例写成普遍规律或因果结论。

教师参考解答|同频曲线与双轴核对

教师参考解答|答案与说明 1

  • 所用数据与字段:同一日期索引的价格与成交量;单位分别为元、万股;这里用确定性课堂示例,不代表真实公司。

教师参考解答|代码 1

展开代码(代码区可独立滚动)
import pandas as pd, matplotlib.pyplot as plt  # 导入表格工具以构造、对齐和核对数据
frame=pd.DataFrame({'price':[10,10.5,10.2,10.8],'volume':[120,150,110,180]},index=pd.date_range('2025-01-01',periods=4))  # 构造带业务字段的数据框输入
standardized_frame=(frame-frame.mean())/frame.std(ddof=0)  # 构造带业务字段的数据框输入
ax=standardized_frame.plot(figsize=(7,3.3),title='教学示例,非市场观测|标准化单轴核对')  # 生成带依据边界的核对图
ax.set_ylabel('标准差单位'); ax.legend(['价格|教学示例,非市场观测','成交量|教学示例,非市场观测']); plt.tight_layout(); plt.show()  # 在图例持续声明依据边界
assert frame.index.is_monotonic_increasing and standardized_frame.mean().abs().lt(1e-12).all()  # 构造带业务字段的数据框输入
print('教学示例,非市场观测|标准化输入描述统计')  # 在孤立输出表头保留依据边界
print(frame.describe())  # 输出教学示例描述统计

教师参考解答|答案与说明 2

  • 拓展应用答案|移动平均交叉教学示例(非市场观测)

教师参考解答|代码 2

展开代码(代码区可独立滚动)
alternative_series=pd.Series([20,20.4,20.1,20.8,21.2,20.9,21.5,21.8],index=pd.date_range('2025-02-07',periods=8,freq='W-FRI'),name='method_fixture_value')  # 构造不对应市场资产的周度教学示例
moving_average_frame=pd.DataFrame({'value':alternative_series})  # 保存原始示例数据序列以便核对
moving_average_frame['fast_ma']=alternative_series.rolling(2).mean()  # 计算两周快速均线
moving_average_frame['slow_ma']=alternative_series.rolling(3).mean()  # 计算三周慢速均线
moving_average_frame['cross_up']=moving_average_frame['fast_ma'].gt(moving_average_frame['slow_ma'])&moving_average_frame['fast_ma'].shift(1).le(moving_average_frame['slow_ma'].shift(1))  # 仅标记快速线由下向上穿越的周
ax=moving_average_frame[['value','fast_ma','slow_ma']].plot(figsize=(7,3.3),title='教学示例,非市场观测|移动平均交叉')  # 绘制带可见依据边界的新案例图
ax.set_ylabel('示例数据数值'); ax.legend(['示例数据序列','2周均线','3周均线'],title='教学示例,非市场观测'); plt.tight_layout(); plt.show()  # 在图例标题持续声明依据边界
assert moving_average_frame['cross_up'].equals((moving_average_frame['fast_ma']>moving_average_frame['slow_ma'])&(moving_average_frame['fast_ma'].shift(1)<=moving_average_frame['slow_ma'].shift(1)))  # 另行核对交叉布尔定义
print('教学示例,非市场观测|移动平均新案例表')  # 在新案例表前持续声明依据边界
print(moving_average_frame)  # 输出新案例前原值、两条均线与交叉状态

教师参考解答|答案与说明 3

  • 解释答案:同一纵轴比较要求时间频率与单位可比;标准化曲线只比较相对变化,双轴缩放可能制造视觉关系,移动平均交叉也不是收益依据。
  • 拓展应用答案:上方拓展应用代码把对象替换为中性周度序列,保持“原值→快/慢均线→由下向上交叉”步骤,输出交叉布尔列并用等价布尔表达式检查;它只验证绘图与交叉识别,不构成交易信号。
  • 参考结果:标准化单轴图、描述统计,以及标明“教学示例,非市场观测”的移动平均图与交叉状态表。另行核对:逐周手算一个均线值和一次交叉布尔值。
  • 常见错误:随机路径使用真实公司名;双轴缩放制造关系;把移动平均交叉当收益信号。